package com.stormragetech.arthas.serialize.convertor;

import com.stormragetech.arthas.common.constant.Constant;
import com.stormragetech.arthas.common.exception.ArthasException;
import com.stormragetech.arthas.common.util.Assert;
import lombok.extern.log4j.Log4j2;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * description: model convertor
 *
 * @author: Xue Bin
 * @version: 1.0.0-SNAPSHOT
 */
@Log4j2
public class ModelConvertor<T> implements Convertor {

    private Map<String, List<String>> v;
    private Class<T> c;

    private T target;

    public ModelConvertor(Map<String, List<String>> v, Class<T> c) throws ArthasException {
        Assert.notNull(v, "the convert source value can not be null !!!");
        Assert.notNull(c, "the convert target class type can not be null !!!");
        this.v = v;
        this.c = c;
        conv();
    }

    private void conv() throws ArthasException {
        try {
            target = c.newInstance();
        } catch (Exception e) {
            throw new ArthasException(Constant.CONV_ERR_CODE, Constant.CONV_ERR_MODLE, ArthasException.SYS_ERR, e);
        }
        Field[] fields = target.getClass().getDeclaredFields();
        for (Field f : fields) {
            String key = f.getName();
            f.setAccessible(true);
            if (ConvertProcessor.isArray(f.getType())) {
                List<String> value = v.get(key);
                if (null == value || value.size() <= 0) {
                    continue;
                }
                Convertor<?> con = new ArrayConvertor<>(value, f.getType());
                try {
                    f.set(target, con.convert());
                } catch (IllegalAccessException e) {
                    throw new ArthasException(Constant.CONV_ERR_CODE, Constant.CONV_ERR_MODLE, ArthasException.SYS_ERR, e);
                }
            } else if (ConvertProcessor.isPrimitive(f.getType())) {
                if (null == v.get(key) || v.get(key).size() <= 0) {
                    continue;
                }
                String value = v.get(key).get(0);
                if (null == value) {
                    continue;
                }
                @SuppressWarnings("unchecked")
                Convertor<?> con = new PrimitiveConvertor(value, f.getType());
                try {
                    f.set(target, con.convert());
                } catch (IllegalAccessException e) {
                    throw new ArthasException(Constant.CONV_ERR_CODE, Constant.CONV_ERR_MODLE, ArthasException.SYS_ERR, e);
                }
            } else {
                log.info("type is {}, the model serialize only support primitive and array type !!!", f.getType());
            }
        }
    }

    @Override
    public T convert() throws ArthasException {
        return target;
    }

}
